﻿Imports System.Collections.Concurrent
Imports System.Reflection
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Runa.Common.Helper
Imports Runa.Core
Imports Runa.UI.Input
Imports Runa.Resources.ResourceManager
Imports Runa.Core.Services
Imports Runa.Foundation.Collections
Imports Runa.Foundation.CompoentModel
Imports Runa.Foundation.Messaging
Imports Runa.Foundation.Threading
Imports Runa.UI.Effects
Imports Runa.UI.Threading
Imports Microsoft.Xna.Framework.Input
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports Runa.UI.Animation
Imports Runa.UI.Styles
Imports Runa.UI.Compoents
Imports Runa.UI.Xaml
Imports Runa.UI.Metadata
Imports Runa.Resources.ContentManagers

Namespace Global.Runa.UI.Controls

    Public Enum BordStyle As Integer
        None = 0
        Thick = 1
        Fixed3D = 2
    End Enum

    Public Enum DockType As Integer
        Free = 0
        Left = 1
        Right = 2
        Bottom = 3
        Top = 4
    End Enum

#If Not WINDOWS_PHONE Then
    <DebuggerDisplay("Name = {Name}, Type = {Type}")>
    Public MustInherit Class UIElementBase
#Else
    Public MustInherit Class UIElementBase
#End If
        Implements IDisposable
        Implements IInputElement
        Implements IAnimatable
        Implements IMessageFilter

        Public Event AnimationBegin(sender As Object, e As System.EventArgs(Of AnimationBase)) Implements Animation.IAnimatable.AnimationBegin
        Public Event AnimationEnd(sender As Object, e As System.EventArgs(Of AnimationBase)) Implements Animation.IAnimatable.AnimationEnd

        Public Event BoundsChange(sender As Object, e As System.EventArgs) Implements IInputElement.BoundsChange
        Public Event Click(sender As Object, e As MouseInputEventArgs) Implements IInputElement.Click
        Public Event KeyDown(sender As Object, e As KeyboradInputEventArgs) Implements IInputElement.KeyDown
        Public Event KeyUp(sender As Object, e As KeyboradInputEventArgs) Implements IInputElement.KeyUp
        Public Event MouseEnter(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseEnter
        Public Event MouseLeave(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseLeave
        Public Event MouseLeftButtonDown(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseLeftButtonDown
        Public Event MouseLeftButtonUp(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseLeftButtonUp
        Public Event MouseMove(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseMove
        Public Event MouseRightButtonDown(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseRightButtonDown
        Public Event MouseRightButtonUp(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseRightButtonUp
        Public Event MouseWheel(sender As Object, e As MouseInputEventArgs) Implements IInputElement.MouseWheel

        Protected _AbsoluteBounds As Rectangle
        Protected _Animations As List(Of AnimationBase)
        Protected _Bounds As Rectangle
        Protected _DrawBounds As Rectangle
        Protected _Parent As UIElementBase
        Protected _Rotation As Single
        Protected _Size As Vector2
        Protected _Location As Vector2

        Protected _IsEnabled As Boolean
        Protected _IsKeyboardFocused As Boolean
        Protected _IsKeyboardFocusWithin As Boolean
        Protected _IsMouseCaptured As Boolean
        Protected _IsMouseDirectlyOver As Boolean
        Protected _IsStylusCaptured As Boolean
        Protected _IsStylusDirectlyOver As Boolean
        Protected _IsStylusOver As Boolean
        Protected _Game As Game
        Protected _Frame As Frame
        Protected _Effect As WpfEffectBase

        Protected Property IsUseDrawBounds As Boolean
        Protected Property OldScrollWheelValue As Integer

        Protected ReadOnly Property ResourceContentManager() As ResourceStreamContentManager
            Get
                Return New ResourceStreamContentManager(Game.Services, GetType(UIElementBase).Assembly.GetName().Name, GetType(UIElementBase).Assembly)
            End Get
        End Property

        Protected ReadOnly Property Type() As String
            Get
                Return Me.GetType().FullName
            End Get
        End Property

        Private _Opacity As Single
        Private _Style As Style
        Private _Visible As Boolean
        Private _IsActive As Boolean = False
        Private _IsMouseOnUIElement As Boolean

        <XamlAware(IsPlainType:=False, ElementName:="Background", Initializer:=GetType(Texture2DObjectConverter))>
        Public Property Background As Texture2DObject
        Public Property Children As ObservableCollection(Of UIElementBase)

        <XamlAware(IsPlainType:=False, ElementName:="Cursor", Initializer:=GetType(Texture2DObjectConverter))>
        Public Property Cursor() As Texture2DObject
        Public Property Dispatcher() As Dispatcher
        Public Property IsAnyKeyDown() As Boolean
        Public Property IsHitTest() As Boolean
        Public Property IsMouseLeftButtonDown() As Boolean
        Public Property IsMouseLeftButtonUp() As Boolean
        Public Property IsMouseRightButtonDown() As Boolean
        Public Property IsMouseRightButtonUp() As Boolean
        Public Property IsMouseWheel() As Boolean
        Public Property MousePosition() As Vector2
        Public Property MouseState() As MouseState

        <XamlAware(IsPlainType:=True, ElementName:="Name")>
        Public Property Name() As String
        Public Property Orgin() As Vector2
        Public Property PressKeys() As Keys()
        Public Property ScrollWheelValueDifference() As Integer
        Public Property SpriteBatch() As SpriteBatch
        Public Property SpriteEffect() As SpriteEffects

        <XamlAware(IsPlainType:=True, ElementName:="Visible")>
        Public Property Visible() As Boolean
            Get
                If Me.Parent IsNot Nothing Then
                    Return Me._Visible And Me.Parent.Visible
                Else
                    Return Me._Visible
                End If
            End Get
            Set(value As Boolean)
                Me._Visible = value
            End Set
        End Property

        <XamlAware(IsPlainType:=False, ElementName:="Dock", Initializer:=GetType(DockTypeConverter))>
        Public Property Dock() As DockType = DockType.Free

        <XamlAware(IsPlainType:=True, ElementName:="ZIndex")>
        Public Property ZIndex() As Single

        Public Property Focusable() As Boolean Implements IInputElement.Focusable

        Friend Shared ReadOnly Property SafeNativeMethods() As ISafeNativeMethods
            Get
                Return Runa.UI.Threading.Dispatcher.SafeNativeMethods
            End Get
        End Property

        Public Property IsActive() As Boolean
            Get
                Return Me._IsActive
            End Get
            Protected Friend Set(value As Boolean)
                Me._IsActive = value
                For Each item In Me.Children
                    item.IsActive = value
                Next
                If Me.GetType() Is GetType(ContentControl) Then
                    CType(Me, ContentControl).Content.IsActive = value
                End If
            End Set
        End Property

        <XamlAware(IsPlainType:=True, ElementName:="IsEnabled")>
        Public Property Enable() As Boolean
            Get
                Return Me._IsEnabled
            End Get
            Set(value As Boolean)
                Me._IsEnabled = value
            End Set
        End Property

        Public Property Frame() As Frame
            Get
                Return Me._Frame
            End Get
            Friend Set(value As Frame)
                Me._Frame = value
            End Set
        End Property

        Public ReadOnly Property IsEnabled() As Boolean Implements IInputElement.IsEnabled
            Get
                Return Me._IsEnabled
            End Get
        End Property

        Public ReadOnly Property IsKeyboardFocused() As Boolean Implements IInputElement.IsKeyboardFocused
            Get
                Return Me._IsKeyboardFocused
            End Get
        End Property

        Public ReadOnly Property IsKeyboardFocusWithin() As Boolean Implements IInputElement.IsKeyboardFocusWithin
            Get
                Return Me._IsKeyboardFocusWithin
            End Get
        End Property

        Public ReadOnly Property IsMouseCaptured As Boolean Implements IInputElement.IsMouseCaptured
            Get
                Return Me._IsMouseCaptured
            End Get
        End Property

        Public ReadOnly Property IsMouseDirectlyOver() As Boolean Implements IInputElement.IsMouseDirectlyOver
            Get
                Return Me._IsMouseDirectlyOver
            End Get
        End Property

        Public ReadOnly Property IsMouseOver() As Boolean Implements IInputElement.IsMouseOver
            Get
                Return Me._IsMouseOnUIElement
            End Get
        End Property

        Public ReadOnly Property IsStylusCaptured() As Boolean Implements IInputElement.IsStylusCaptured
            Get
                Return Me._IsStylusCaptured
            End Get
        End Property

        Public ReadOnly Property IsStylusDirectlyOver() As Boolean Implements IInputElement.IsStylusDirectlyOver
            Get
                Return Me._IsStylusDirectlyOver
            End Get
        End Property

        Public ReadOnly Property IsStylusOver() As Boolean Implements IInputElement.IsStylusOver
            Get
                Return Me._IsStylusOver
            End Get
        End Property

        Public Property AbsoluteBounds() As Rectangle
            Get
                'If Me.Parent IsNot Nothing AndAlso Me._AbsoluteBounds.Intersects(Me.Parent.AbsoluteBounds) Then
                '    Dim area = Rectangle.Intersect(Me._AbsoluteBounds, Me.Parent.AbsoluteBounds)
                '    With Me._AbsoluteBounds.Location
                '        'Me.DrawBounds = New Rectangle(.X - area.X, .Y - area.Y, area.Width, area.Height)
                '        area.Location = Me._AbsoluteBounds.Location
                '    End With
                '    Return area
                'Else
                '    Return Me._AbsoluteBounds
                'End If
                Return Me._AbsoluteBounds
            End Get
            Protected Set(ByVal value As Rectangle)
                Me._AbsoluteBounds = value
            End Set
        End Property

        Public Overridable Property AbsoluteRotation() As Single
            Get
                If (Not Me.Parent Is Nothing) Then
                    Return (Me._Rotation + Me.Parent.AbsoluteRotation)
                End If
                Return Me._Rotation
            End Get
            Set(ByVal value As Single)
                If (Me._Parent Is Nothing) Then
                    Me._Rotation = value
                Else
                    Me._Rotation = (value - Me.Parent.AbsoluteRotation)
                End If
            End Set
        End Property

        Public Property Animations() As List(Of AnimationBase) Implements IAnimatable.Animations
            Get
                Return Me._Animations
            End Get
            Set(ByVal value As List(Of AnimationBase))
                Me._Animations = value
            End Set
        End Property

        Public ReadOnly Property AnimationCompeleted() As Boolean
            Get
                Return (From item In Me.Animations Where item.IsFinished = False Select item).Count() = 0
            End Get
        End Property

        Public Property BordStyle() As BordStyle = BordStyle.None
        Public Property Tag() As Object

        Public Property Bounds() As Rectangle
            Get
                Return Me._Bounds
            End Get
            Set(ByVal value As Rectangle)
                If (value <> Me._Bounds) Then
                    Me._Bounds = value
                    Me._Location = New Vector2(CSng(value.X), CSng(value.Y))
                    Me._Size = New Vector2(CSng(value.Width), CSng(value.Y))
                    Me.OnBoundsChange()
                End If
            End Set
        End Property

        Public Overridable Property DrawBounds() As Rectangle
            Get
                If Me.IsUseDrawBounds Then
                    Return Me._DrawBounds
                End If
                Return Me.AbsoluteBounds
            End Get
            Set(ByVal value As Rectangle)
                Me._DrawBounds = value
                Me.IsUseDrawBounds = True
            End Set
        End Property

        Public Property Effect() As WpfEffectBase
            Get
                Return Me._Effect
            End Get
            Set(value As WpfEffectBase)
#If WINDOWS_PHONE Then
                Me._Effect = value
#Else
                Me._Effect = value.Clone()
#End If
            End Set
        End Property

        Public Property Game() As Game
            Get
                Return _Game
            End Get
            Friend Set(value As Game)
                Me._Game = value
            End Set
        End Property

        Public Property IsMouseOnUIElement() As Boolean
            Get
                Return Me._IsMouseOnUIElement
            End Get
            Set(ByVal value As Boolean)
                If Me._IsMouseOnUIElement = True And value = False Then
                    RaiseEvent MouseLeave(Me, New MouseInputEventArgs(MessageType.WM_MOUSEMOVE, Mouse.GetState(), Nothing))
                End If
                Me._IsMouseOnUIElement = value
            End Set
        End Property

        <XamlAware(IsPlainType:=False, Initializer:=GetType(Vector2Converter))>
        Public Overridable Property Location() As Vector2
            Get
                Return Me._Location
            End Get
            Set(ByVal value As Vector2)
                If (Me._Location <> value) Then
                    Me._Location = value
                    Me._Bounds = New Rectangle(CInt(value.X), CInt(value.Y), CInt(Me.Size.X), CInt(Me.Size.Y))
                    Me.OnBoundsChange()
                End If
            End Set
        End Property

        Public Property Opacity() As Single
            Get
                If Me.Parent IsNot Nothing Then
                    Return Me._Opacity * Me.Parent.Opacity
                Else
                    Return Me._Opacity
                End If
            End Get
            Set(ByVal value As Single)
                If (((Me._Opacity <> value) AndAlso (value >= 0.0!)) AndAlso (value <= 1.0!)) Then
                    Me._Opacity = value
                    If (Not Me.Effect Is Nothing) Then
                        Me.Effect.Opacity = value
                    End If
                End If
            End Set
        End Property

        Public Property Parent() As UIElementBase
            Get
                Return Me._Parent
            End Get
            Set(ByVal value As UIElementBase)
                If Me._Parent IsNot value Then
                    ' For different types of parent.
                    If TypeOf value Is Panel Then
                        value.Children.Add(Me)
                    ElseIf TypeOf value Is ContentControl Then
                        TryCast(value, ContentControl).Content = Me
                    End If
                    Me._Parent = value
                    Me.IsActive = value.IsActive
                    Me.Dispatcher = value.Dispatcher
                    Me.Dispatcher = value.Dispatcher
                    Me.ZIndex = value.ZIndex
                    If value Is Nothing Then
                        SafeNativeMethods.RegisterWindowClass(Me)
                    End If
                    Me.OnBoundsChange()
                End If
            End Set
        End Property

        Public ReadOnly Property RelativePosition() As Vector2
            Get
                Return (Me.MousePosition - Me.Location)
            End Get
        End Property

        Public Property Rotation() As Single
            Get
                Return Me._Rotation
            End Get
            Set(ByVal value As Single)
                If (Me._Rotation <> value) Then
                    Me._Rotation = value
                End If
            End Set
        End Property

        <XamlAware(IsPlainType:=False, Initializer:=GetType(Vector2Converter))>
        Public Overridable Property Size() As Vector2
            Get
                Return Me._Size
            End Get
            Set(ByVal value As Vector2)
                If (Me._Size <> value) Then
                    Me._Size = value
                    Me._Bounds = New Rectangle(CInt(Me._Location.X), CInt(Me._Location.Y), CInt(Me._Size.X), CInt(Me._Size.Y))
                    Me.OnBoundsChange()
                End If
            End Set
        End Property

        Public Overridable Property Style() As Style
            Get
                Return Me._Style
            End Get
            Set(ByVal value As Style)
                Me._Style = value
            End Set
        End Property

        Public Sub New(ByVal g As Game)
            Me.New("")
            Me.Name = Me.GetType().Name & "_" & BytesToString(Guid.NewGuid().ToByteArray())
            Me.Game = g
            Me.Initialize()
        End Sub

        Protected Sub New(ByVal Name As String, Optional ByVal frame As Frame = Nothing)
            Me._Frame = frame
            Me.Game = If(frame IsNot Nothing, frame.Game, Nothing)
            Me.Orgin = Vector2.Zero
            Me.SpriteEffect = SpriteEffects.None
            Me.Children = New ObservableCollection(Of UIElementBase)
            Me._Location = Vector2.Zero
            Me._Size = Vector2.Zero
            Me.ZIndex = 1.0!
            Me.IsUseDrawBounds = False
            Me.Visible = True
            Me._Opacity = 1.0!
            Me.IsHitTest = True
            Me._Animations = New List(Of AnimationBase)
            Me.IsMouseLeftButtonDown = False
            Me.IsMouseLeftButtonUp = True
            Me.IsMouseRightButtonDown = False
            Me.IsMouseRightButtonUp = True
            Me._IsMouseOnUIElement = False
            Me.IsMouseWheel = False
            Me.ScrollWheelValueDifference = 0
            Me.MousePosition = Vector2.Zero
            Me.IsAnyKeyDown = False
            AddHandler Me.Children.CollectionChanged, AddressOf Children_CollectionChanged
            Me.Name = Name
            Me.Initialize()
        End Sub

        Public Sub New(ByVal Name As String, ByVal Parent As UIElementBase)
            Me.New(Name, If(Parent IsNot Nothing, Parent.Frame, Nothing))
            If Parent Is Nothing Then Exit Sub
            Me.Parent = Parent
            Me.Game = Parent.Game
            AddHandler Me._Parent.BoundsChange, New EventHandler(AddressOf Me._Parent_BoundsChange)
        End Sub

        Public Sub OnAnimationBegin(sender As Object, e As System.EventArgs(Of Animation.AnimationBase)) Implements Animation.IAnimatable.OnAnimationBegin
            RaiseEvent AnimationBegin(sender, e)
        End Sub

        Public Sub OnAnimationEnd(sender As Object, e As System.EventArgs(Of Animation.AnimationBase)) Implements Animation.IAnimatable.OnAnimationEnd
            RaiseEvent AnimationEnd(sender, e)
        End Sub

        Public Function IsSubControl(ByVal obj As UIElementBase) As Boolean
            For Each ctrl As UIElementBase In Me.Children
                If ctrl Is obj Then
                    Return True
                End If
                If ctrl.Children.Count > 0 Then
                    For Each child As UIElementBase In ctrl.Children
                        If child.IsSubControl(obj) Then
                            Return True
                        End If
                    Next
                End If
                If TypeOf ctrl Is ContentControl Then
                    If CType(ctrl, ContentControl).Content IsNot Nothing Then
                        If CType(ctrl, ContentControl).Content Is obj Then
                            Return True
                        End If
                    End If
                End If
            Next
            Return False
        End Function

        ''' <summary>
        ''' Find a control by the given name.
        ''' </summary>
        ''' <param name="name"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function FindControl(ByVal name As String) As UIElementBase
            If Me.Name = name Then Return Me
            For Each ctrl As UIElementBase In Me.Children
                If ctrl.Name = name Then
                    Return ctrl
                End If
                If ctrl.Children.Count > 0 Then
                    For Each child As UIElementBase In ctrl.Children
                        Dim result = child.FindControl(name)
                        If result IsNot Nothing Then Return result
                    Next
                End If
                If TypeOf ctrl Is ContentControl Then
                    If CType(ctrl, ContentControl).Content IsNot Nothing Then
                        If CType(ctrl, ContentControl).Content.Name = name Then
                            Return CType(ctrl, ContentControl).Content
                        End If
                    End If
                End If
            Next
            If Me.GetType() Is GetType(ContentControl) Then
                If CType(Me, ContentControl).Content IsNot Nothing Then
                    If CType(Me, ContentControl).Content.Name = name Then
                        Return CType(Me, ContentControl).Content
                    End If
                End If
            End If
            Return Nothing
        End Function

        ''' <summary>
        ''' Find the controls by the given type.
        ''' </summary>
        ''' <param name="typ"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function FindControl(ByVal typ As Type) As List(Of UIElementBase)
            Dim lst As New List(Of UIElementBase)
            If Me.GetType() Is typ Then lst.Add(Me)
            For Each ctrl As UIElementBase In Me.Children
                If ctrl.GetType() Is typ Then
                    lst.Add(ctrl)
                End If
                If ctrl.Children.Count > 0 Then
                    For Each child As UIElementBase In ctrl.Children
                        If child.GetType() Is typ Then
                            lst.Add(child)
                        End If
                        Dim result = child.FindControl(typ)
                        lst.AddRange(result)
                    Next
                End If
                If TypeOf ctrl Is ContentControl Then
                    If CType(ctrl, ContentControl).Content IsNot Nothing Then
                        If CType(ctrl, ContentControl).Content.GetType() Is typ Then
                            Dim result = CType(ctrl, ContentControl).Content
                            lst.Add(result)
                            lst.AddRange(result.FindControl(typ))
                        End If
                    End If
                End If
            Next
            If Me.GetType() Is GetType(ContentControl) Then
                If CType(Me, ContentControl).Content IsNot Nothing Then
                    If CType(Me, ContentControl).Content.GetType() Is typ Then
                        lst.Add(CType(Me, ContentControl).Content)
                    End If
                End If
            End If
            Return lst
        End Function

        ''' <summary>
        ''' Use this function to refresh the layout of this control.
        ''' </summary>
        ''' <remarks></remarks>
        Public Overridable Sub UpdateLayout()
            For Each child As UIElementBase In Me.Children
                If child.Size = Vector2.Zero Then child.Size = Me.Size
                If child.Children.Count > 0 Then
                    For Each c As UIElementBase In child.Children
                        c.UpdateLayout()
                    Next
                End If
            Next
        End Sub

        Private Sub _Parent_BoundsChange(ByVal sender As Object, ByVal e As EventArgs)
            Me.OnBoundsChange()
        End Sub

        Private Sub Children_CollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
            Dim items = If(e.NewItems, New List(Of UIElementBase))
            If e.Action = NotifyCollectionChangedAction.Remove Then
                For Each ui As UIElementBase In items
                    SafeNativeMethods.UnRegisterWindowClass(ui)
                Next
            ElseIf e.Action = NotifyCollectionChangedAction.Add Then
                For Each ui As UIElementBase In items
                    ui._Frame = Me.Frame
                    If ui.Size = Vector2.Zero Then
                        ui.Size = Me.Size
                    End If
                    SafeNativeMethods.RegisterWindowClass(ui)
                Next
            ElseIf e.Action = NotifyCollectionChangedAction.Reset Then
                For Each ui As UIElementBase In items
                    SafeNativeMethods.UnRegisterWindowClass(ui)
                Next
            End If
        End Sub

        Protected Overridable Sub OnBoundsChange()
            If Me.Parent Is Nothing Then
                Me._AbsoluteBounds = Me.Bounds
            Else
                Me._AbsoluteBounds = New Rectangle((Me.Parent.AbsoluteBounds.X + Me.Bounds.X), (Me.Parent.AbsoluteBounds.Y + Me.Bounds.Y), Me.Bounds.Width, Me.Bounds.Height)
            End If
            If Me.Parent IsNot Nothing Then
                If Me.Size = Vector2.Zero Then
                    Me.Size = Parent.Size
                End If
            End If
            RaiseEvent BoundsChange(Me, Nothing)
            Dim ctr As UIElementBase
            For Each ctr In Me.Children
                ctr.OnBoundsChange()
            Next
        End Sub

        Protected Friend Function HitTest(ByVal pos As Point) As Boolean
            Dim result = Me.IsMouseOnUIElement
            If Me.IsHitTest Then
                If Me.AbsoluteBounds.Contains(pos) Then
                    result = True
                Else
                    result = False
                    Me.IsMouseOnUIElement = False
                End If
            End If
            Return result
        End Function

        Private Function DispachMessage(ByRef m As Foundation.Messaging.Message) As Boolean Implements Foundation.Messaging.IMessageFilter.DispachMessage
            Return True
        End Function

        Private Function PreFilterMessage(ByRef m As Foundation.Messaging.Message) As Boolean Implements Foundation.Messaging.IMessageFilter.PreFilterMessage
            Return True
        End Function

        Private Function TranslateMessage(ByRef m As Foundation.Messaging.Message) As Boolean Implements Foundation.Messaging.IMessageFilter.TranslateMessage
            Return True
        End Function

        Public Overridable Function WndProc(ByRef m As Foundation.Messaging.Message) As Boolean Implements Foundation.Messaging.IMessageFilter.WndProc
            If Me.IsHitTest And Me.IsActive Then
                If Me.HitTest(m.Pt) Then
                    Dim e As New InputEventArgs(Point.Zero, MessageType.WM_USER)
                    Select Case m.Message
                        Case MessageType.WM_MOUSEWHEEL
                            Dim cpi = CType(m.LParm, IChangedPropertyInf(Of Object))
                            e = New MouseInputEventArgs(m.Message, Mouse.GetState, cpi) With {.MouseWheelDelta = cpi.NewValue}
                            RaiseEvent MouseWheel(Me, e)
                        Case MessageType.WM_KEYDOWN
                            e = New KeyboradInputEventArgs(m.Message, Nothing, Nothing)
                            RaiseEvent KeyDown(Me, e)
                        Case MessageType.WM_KEYUP
                            e = New KeyboradInputEventArgs(m.Message, Keyboard.GetState, Nothing)
                            RaiseEvent KeyUp(Me, e)
                        Case MessageType.WM_MOUSEMOVE
                            If Me.IsMouseOnUIElement = False Then
                                e = New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                                RaiseEvent MouseEnter(Me, e)
                                Me.IsMouseOnUIElement = True
                            End If
                            Dim e1 As New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                            RaiseEvent MouseMove(Me, e1)
                            e.Handled = e.Handled Or e1.Handled
                        Case MessageType.WM_LBUTTONDOWN
                            e = New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                            RaiseEvent MouseLeftButtonDown(Me, e)
                            Me.IsMouseLeftButtonUp = False
                            Me.IsMouseLeftButtonDown = True
                        Case MessageType.WM_LBUTTONUP
                            e = New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                            RaiseEvent MouseLeftButtonUp(Me, e)
                            If Me.IsMouseLeftButtonDown Then
                                Dim e1 As New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                                RaiseEvent Click(Me, e1)
                                e.Handled = e.Handled Or e1.Handled
                            End If
                            Me.IsMouseLeftButtonUp = True
                            Me.IsMouseLeftButtonDown = False
                        Case MessageType.WM_RBUTTONDOWN
                            e = New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                            RaiseEvent MouseRightButtonDown(Me, e)
                            Me.IsMouseRightButtonUp = False
                            Me.IsMouseRightButtonDown = True
                        Case MessageType.WM_RBUTTONUP
                            e = New MouseInputEventArgs(m.Message, Mouse.GetState, Nothing)
                            RaiseEvent MouseRightButtonUp(Me, e)
                            Me.IsMouseRightButtonUp = True
                            Me.IsMouseRightButtonDown = False
                    End Select
                    Return e.Handled
                End If
            End If
            Return False
        End Function

        Public Overridable Sub Draw(ByVal SpriteBatch As SpriteBatch)
            If Me.Visible AndAlso Me.IsMouseOnUIElement Then
                Me.DrawCursor(SpriteBatch)
                SpriteBatch.Begin()
                Select Case Me.BordStyle
                    Case BordStyle.None
                    Case BordStyle.Thick
                        Dim box = Me.DrawBounds.GenerateRetangleTexture(SpriteBatch.GraphicsDevice)
                        SpriteBatch.Draw(box, Me.Location + New Vector2(1, 1), Color.White)
                    Case BordStyle.Fixed3D
                End Select
                SpriteBatch.End()
            End If
        End Sub

        Public Overridable Sub DrawCursor(ByVal SpriteBatch As SpriteBatch)
            If Me.Cursor IsNot Nothing AndAlso Me.Cursor.Texture IsNot Nothing Then
                Dim MouseState As MouseState = Mouse.GetState
                SpriteBatch.Begin()
                SpriteBatch.Draw(Me.Cursor.Texture, New Vector2(CSng(MouseState.X), CSng(MouseState.Y)), Color.White)
                SpriteBatch.End()
            End If
        End Sub

        Public Overridable Sub DrawFrame(ByVal SpriteBatch As SpriteBatch)
        End Sub

        Protected Overridable Sub Initialize()
        End Sub

        Public Overridable Sub Update(ByVal gameTime As GameTime)
            For i As Integer = 0 To Me.Animations.Count - 1
                Try
                    Me.Animations(i).Updata(gameTime)
                Catch ex As Exception
                    Exit Try
                End Try
            Next
            If Not Me.Effect Is Nothing Then
                Me.Effect.UpdataParameters(gameTime)
            End If
        End Sub

#Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: dispose managed state (managed objects).
                    Dim ui As UIElementBase
                    For Each ui In Me.Children
                        ui.Dispose()
                    Next
                    If Me.Parent IsNot Nothing AndAlso Me.Parent.Children.Contains(Me) Then
                        Me.Parent.Children.Remove(Me)
                    End If
                    SafeNativeMethods.UnRegisterWindowClass(Me)
                End If
                ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
                ' TODO: set large fields to null.
            End If
            Me.disposedValue = True
        End Sub

        ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
        'Protected Overrides Sub Finalize()
        '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        '    Dispose(False)
        '    MyBase.Finalize()
        'End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class

End Namespace